package com.wei.io;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.stream.Stream;

import com.wei.BaiduSourceProvider;
import com.wei.model.MapConfig;
import com.wei.model.TileCoord;

import lombok.extern.log4j.Log4j;

/**
 * 
 * @author kerry-weic
 * @date 2019年5月5日
 */
@Log4j
public class FailUrlLoader {

	private File[] files;
	private BaiduSourceProvider tmsSourceProvider ;
	private String imageStragePath;
	private int counter;
	private MapConfig mapConfig = MapConfigLoader.getInstance().getMapConfig();
	
	public FailUrlLoader() {
		try {
			String path = mapConfig.getFailUrlPath();
			this.imageStragePath = mapConfig.getImageStragePath();
			tmsSourceProvider = new BaiduSourceProvider(mapConfig);
			File file = new File(path);
			files = file.listFiles(new FileFilter() {
				
				@Override
				public boolean accept(File pathname) {
					
					return pathname.getName().contains("fail-url.log");
				}
			});
			if(files == null || files.length == 0) {
				log.info("未找到待读取的文件");
			}
		} catch (Exception e) {
			log.error("FailUrlLoader实例初始化失败", e);
			throw e;
		}
	}
	
	public void read() {
		Stream.of(files).forEach(f -> {
			try {
				BufferedReader in = new BufferedReader(new FileReader(f));
				String line = null;
				int i = 0;
				while ((line = in.readLine()) != null) {
					i ++;
					TileCoord tc = this.parseLine(line);
					tc.setIndex(i);
					dowloadImage(tc);
					if(i % 1000 == 0) {
						log.info(f.getName()+"当前读取行数:"+i);
					}
				}
				in.close();
				log.info(f.getName() +"文件读取解析完毕");
			} catch (IOException e) {
				log.error("文件读取出现未知异常", e);
			}
			
		});
		
	}
	
	public synchronized void dowloadImage(TileCoord tileCoord) {
		String imageUrl = tmsSourceProvider.getRequestUrl(tileCoord);
		String path = this.getImageStragePath(tileCoord);
		try {
			URL url = new URL(imageUrl);
			File file = new File(path);
			URLConnection urlConn = url.openConnection();
			urlConn.setConnectTimeout(1000 * 5);
			urlConn.setRequestProperty("Accept-Encoding", "gzip, deflate");
			urlConn.setRequestProperty("Accept-Language", "zh-CN,en,*");
			urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
			DataInputStream in = new DataInputStream(urlConn.getInputStream());
			DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = in.read(buffer)) > 0) {
				out.write(buffer, 0, len);
			}
			in.close();
			out.close();
			counter = 0;
		}catch(IOException e) { 
			try {
				log.info("图片下载出现异常，等待100ms后重试。imageUrl:"+imageUrl);
				this.wait(100);
			} catch (InterruptedException e1) {
				log.error(e1.getMessage(), e);
			}
			if(counter ++ <= 5) {
				log.info("wait 100ms, counter:"+ counter +",imageUrl:"+imageUrl+", errMsg:"+e.getMessage());
				this.dowloadImage(tileCoord);
			}else {
				log.fatal("imageUrl:"+imageUrl);
				log.error(e.getMessage(), e);
			}
		}
	}
	
	private String getImageStragePath(TileCoord tileCoord) {
		String x = tileCoord.getX() < 0 ? "M"+Math.abs(tileCoord.getX()) : tileCoord.getX()+"";
		String y = tileCoord.getY() < 0 ? "M"+Math.abs(tileCoord.getY()) : tileCoord.getY()+"";
		x = x.substring(0, x.indexOf("."));
		y = y.substring(0, y.indexOf("."));
		String url = imageStragePath;
		url = url.replace("{z}", tileCoord.getZoom() + "");
		url = url.replace("{x}", x);
		this.createPath(url);
		return url + File.separatorChar + y +".png";
	}
	
	
	private TileCoord parseLine(String line) {
		int idx = line.indexOf("imageUrl:") + 9;
		String imageUrl = line.substring(idx, line.indexOf(",", idx));
		return new TileCoord(0, this.parseZ(imageUrl), this.parseX(imageUrl), this.parseY(imageUrl));
	}
	
	private double parseX(String imageUrl) {
		String x = imageUrl.substring(imageUrl.indexOf("&x=") + 3,imageUrl.indexOf("&y"));
		if(x.contains("M")) {
			return -Double.parseDouble(x.replace("M", ""));
		}
		return Double.parseDouble(x);
	}
	
	private double parseY(String imageUrl) {
		String y = imageUrl.substring(imageUrl.indexOf("&y=") + 3,imageUrl.indexOf("&z"));
		if(y.contains("M")) {
			return -Double.parseDouble(y.replace("M", ""));
		}
		return Double.parseDouble(y);
	}
	
	private int parseZ(String imageUrl) {
		String z = imageUrl.substring(imageUrl.indexOf("&z=") + 3);
		return Integer.parseInt(z);
	} 	
	
	private void createPath(String path) {
		File file = new File(path);
		if(!file.exists()) {
			file.mkdirs();
		}
	}
	
	public static void main(String[] args) {
		FailUrlLoader f = new FailUrlLoader();
		f.read();
	}
}
